package generator.utils.java2xml;

import generator.utils.TransformDocs;
import harsh.javatoxml.Java2XML;
import harsh.javatoxml.Exceptions.JXMLException;
import harsh.javatoxml.data.IXMLElement;
import harsh.javatoxml.dom.Domifier;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**Esta clase sirve como herramienta para manipular documentos cuya estructura responde al formato
 * impuesto por la biblioteca Java2xml. Los métodos que implementa permiten realizar modificaciones 
 * o consultas tales como cambiar el nombre de una clase, incorporacion de sentencias import,
 * cambio del nombre de paquete al que pertence una clase, seteo de tipos de variables o tipos de retorno
 * de métodos, obtencion de la sentencia de declaración de una variable, etc.*/

public class DocumentModifier {
	
	/**Constante numérica que indica para inidcar el valor equal de una comparación*/
	protected final int EQUAL =				0;
	
	public static final int FIRST = 		0;
	
	
	/**A continuación una versión reducida de la lista de tags que emplea la biblioteca java2xml para 
	 * representar una clase java como archivo xml*/	
	
	
	/**nombre del elemento xml que indica la presencia de un bloque*/
	public final String BODYMETHOD = 		"block";
	
	/**nombre del elemento xml que indica la presencia de un envío de mensaje a un objeto (llamada a un método)*/
	public final String METHODCALL = 		"send";
	
	/**nombre del elemento xml que indica la presencia de un atributo de una clase u objeto*/
	public final String ATTRIBUTE = 		"field";
	
	/**nombre del elemento xml que sirve para indicar el atributo tipo de una variable, parámetro, función, etc*/
	public final String TYPE = 				"type";
	
	/**nombre del elemento xml que indica el como se llama el archivo xml usualmente recibe el mismo nombre que
	 * la clase a la cual describe.*/
	public final String CLASSFILENAME = 	"java-class-file";
	
	/**nombre del elemento xml que indica el mombre del paquete al que pertenece la clase que representa el
	 * archivo xml.*/
	public final String PACKAGE = 			"package-decl";
	
	/**nombre del elemento xml que indica el nombre de la clase representada por el archivo xml*/
	public final String CLASS = 			"class";
	
	/**nombre del elemento xml que indica la presencia de un parámetro formal de un método*/
	public final String PARAM = 			"formal-argument";
	
	/**nombre del elemento xml que siempre precede a todo argumento formal o conjunto de argumentos formales
	 * de un método, es decir, el nodo padre de {@link PARAM} siempre será un nodo ALLPARAMS*/
	public final String ALLPARAMS = 		"formal-arguments";
	
	/**nombre del elemento xml que indica la presencia de una declaración de método*/
	public final String METHOD = 			"method";
	
	/**nombre del elemento xml que indica la presencia de una declaración del método construtor de una clase java*/
	public final String CONSTRUCTOR = 		"constructor";
	
	/**nombre del elemento xml que indica la presencia de una sentencia de asignación*/
	public final String ASIGMENT = 			"assignment-expr";
	
	/**nombre del elemento xml que indica la existencia de una referencia a una variable de un método*/
	public final String VARREF = 			"var-ref";
	
	/**nombre del elemento xml que indica la existencia de una sentencia de creación de un objeto*/
	public final String NEW = 				"new";
	
	/**nombre del elemento xml que engloba a los parámetros reales de una llamada a un método*/
	public final String ARGUMENTS = 		"arguments";
	
	/**nombre del elemento xml que indica la presencia de una operación de casting*/
	public final String CASTEXPR = 			"cast-expr";
	
	/**nombre del elemento xml que indica la existencia de una sentencia import al inicio de la clase java*/
	public final String IMPORT = 			"import";
	
	/**nombre del elemento xml que sirve para indicar el objeto al cual se le pretende enviar un mensaje*/
	public final String TARGET = 			"target";
	
	/**nombre del elemento xml que indica la existencia de un acceso a un atributo de un objeto*/
	public final String FIELDACCESS = 		"field-access";
	
	/**nombre del elemento xml que indica la presencia de una declaración de variable dentro del cuerpo de un
	 * método*/
	public final String LOCALVARIABLE = 	"local-variable";
	
	/**nombre del elemento xml que sirve para indicar el lado izquierdo de una sentencia de asignación*/
	public final String ASSIGLEFTVALUE = 	"lvalue";
	
	/**nombre del elemento xml que indica la presencia de una constante numérica*/
	public final String NUMBER = 			"literal-number";
	
	/**nombre del elemento xml que indica la presencia de una cadena alfanumérica*/
	public final String STRING = 			"literal-string";
	
	/**nombre del elemento xml que indica la existencia de una sentencia condicional*/
	public final String BRANCH = 			"if";	

	/**nombre del elemento xml que indica la presencia de una autoreferencia*/
	public final String THIS = 				"this";
	
	/**nombre del elemento xml que indica la existencia de una sentencia return*/
	public final String RETURN = 			"return";
	
	/**nombre del elemento xml que indica el comienzo de la declaración de una interface java*/
	public final String INTERFACE = 		"interface";
				
	/**nombre del elemento xml que indica la presencia de una sentencia throws en la declaración de un método*/
	public final String THROWS = 			"throws";
	
	/**ArrayList que contiene los nombres de los tipos primitivos de java*/		
	private ArrayList<String> primitivesTypes;
	
	/**Es el objeto necesario para evaluar expresiones xpath sobre archivos xml*/
	protected XPath xpath;
	
	/**indica la ruta donde se halla el archivo de estructuras preConstruidas utilizado para
	 * facilitar la tarea llevada a cabo en algunos métodos que ofrece la clase*/
	private final String preBuildStructuresPath = new String("conf//preBuildStructures.xml");
	
	/**Es un documento con estructuras pre-armadas, a modo de templates. Las mismas son utilizadas a la 
	 * hora introducir modificaciones a un documento. Por ejemplo el agregado de una nueva sentencia
	 * import a una clase java provoca que se obtenga el nodo genérico que representa un elemento import para
	 * luego completarlo con los datos correspondientes*/
	protected Document preBuildStructures;
	
	/**Constructor de la clase que retorna una instancia de DocumentModifier a partir de la cual se pueden
	 * efectuar modificaciones sobre documentos que respeten la estructura impuesta por la biblioteca java2xml*/
	public DocumentModifier(){
		
		xpath = XPathFactory.newInstance().newXPath();
		preBuildStructures = TransformDocs.xmlToDom(new File(preBuildStructuresPath)); 
		
		primitivesTypes = new ArrayList<String>();
		primitivesTypes.add("int");
		primitivesTypes.add("long");
		primitivesTypes.add("short");
		primitivesTypes.add("boolean");
		primitivesTypes.add("char");
		primitivesTypes.add("double");
		primitivesTypes.add("float");
		primitivesTypes.add("byte");		
	}
	
	
	/**Incorpora todos los nodos que representan sentencias import del documento source al documento
	 * dest. 
	 * @param source
	 * 			documento de donde se copiarán los nodos que corresponden a sentencias import
	 * @param dest
	 * 			documento  que recibirá	los nodos que representan sentencias import
	 * <BR>NOTA: ambos parámetros representan una clase java según el formato impuesto por java2xml.
	 * Se asegura que, al pretender agregar una sentencia import ya contenida en la clase representada
	 * por dest, la operación no tenga efecto y así evitar la duplicación de imports. 
	 *  */
	public void cloneImports(Document source, Document dest){
		
		try {
			NodeList allImports = (NodeList)xpath.evaluate("//"+IMPORT, source, XPathConstants.NODESET);
			if (allImports != null)
				for (int i = 0; i < allImports.getLength(); i++)					
					addImport(allImports.item(i), dest);				
					
		} catch (XPathExpressionException e) {
				System.out.println("[ERR] error en la clonación de imports");
				e.printStackTrace();
		}
	}
	
	
	/**@return true si el contenido del nodo import ya se encuentra presente en otro nodo import del
	 * 			 documento que corresponde al segundo parámetro. False en caso contrario.*/
	public boolean checkImport(Element nodeImport, Document document) throws XPathExpressionException{
		return (Boolean)xpath.evaluate("//"+IMPORT+"[@module=\""+ nodeImport.getAttribute("module")+"\"]", document, XPathConstants.BOOLEAN);
	}
	
	
	/**Este método inserta una sentencia import sobre el documento pasado como parámetro	 
	 * @param importValue
	 * 				es el nombre del paquete que formará parte de la sentencia import
	 * @param inputDoc
	 * 				documento que representa la clase sobre la que se pretende insertar la
	 * 				sentencia import.
	 * @return org.w3c.dom.Document
	 * 				documento con la sentencia import insertada. 
	 * NOTA: el documento de entrada será modificado como consecuencia de la invocación al método*/
	public void addImport(String importValue, Document inputDoc){
				
		try {
			 Element genericImportNode = (Element)xpath.evaluate("//structure[@id=\"import\"]/"+IMPORT, preBuildStructures, XPathConstants.NODE);
			 genericImportNode.setAttribute("module", importValue);
			 addImport(genericImportNode, inputDoc);			 
		} catch (XPathExpressionException e) {
			System.out.println("[ERR] No se encontro el nodo genérico import");		
		}		
	}	
	
	/**Inserta un nodo correspondiente a una sentencia import dentro de un documento que representa una clase java
	 * sobre la cual se añadirá el import.
	 * NOTA: el nodo es clonado e incorporado al documento y se asegura que no existan imports repetidos dentro de la clase. 
	 * @param foreignImportNode
	 * 				nodo import que será insertado dentro del documento
	 * @param inputDoc
	 * 				documento que representa la clase java que recibirá la inseción del import*/
	public void addImport(Node foreignImportNode, Document inputDoc){
				 
		try {
			if(!this.checkImport((Element)foreignImportNode, inputDoc)){
				Node importNode = inputDoc.importNode(foreignImportNode, true);
				/**se obtiene el nodo donde comienza la declaración de la clase para que la inserción del nodo import
				 * quede por encima, respetando la sintaxis de java*/
				Node classDeclaration = (Node)xpath.evaluate("//"+CLASS, inputDoc, XPathConstants.NODE);
				Node insertionPoint = classDeclaration.getParentNode();
				
				insertionPoint.insertBefore(importNode, classDeclaration);		
			}
		} catch (XPathExpressionException e) {
			System.out.println("[ERR] Falló la inserción del nodo import");
			e.printStackTrace();
		}					
	}
	
	/**Mediante este método se cambia el nombre a una clase java. El método también contempla el 
	 * cambio de nombre de los constructores y del archivo propiamente dicho. También son actualizadas todas 
	 * las referencias al viejo nombre de la clase pero sólo dentro de la clase.
	 * @param nameValue
	 * 				nuevo nombre de la clase
	 * @param document
	 * 				documento que representa la clase a la cual se le pretende cambiar el nombre*/
	public void setClassName(String nameValue, Document document) throws XPathExpressionException{
		
		//se actualizan las referencias al nombre de la clase con el nuevo nombre
		String className = ((String)xpath.evaluate("//"+CLASS+"[1]/@name", document, XPathConstants.STRING));		
		NodeList classRefs = ((NodeList)xpath.evaluate("//"+TYPE+"[@name='"+className+"']", document, XPathConstants.NODESET));
		for (int i = 0; i < classRefs.getLength(); i++)
			((Element)classRefs.item(i)).setAttribute("name", nameValue);
				
		//se obtiene el elemento "java-class-file" y se le setea el atributo name al valor recibido en el primer parámetro del método
		((Element)xpath.evaluate("/"+CLASSFILENAME, document, XPathConstants.NODE)).setAttribute("name", nameValue+".java");
		//se obtiene el elemento "class"(donde comienza la declaración de la clase) y se le setea el atributo name al valor recibido en el primer parámetro del método
		((Element)xpath.evaluate("//"+CLASS+"[1]", document, XPathConstants.NODE)).setAttribute("name", nameValue);
		//se cambian los nombres del/los constructores de la clase.
		NodeList constructors = document.getElementsByTagName(CONSTRUCTOR);
		for (int i = 0; i < constructors.getLength(); i++)
			((Element)constructors.item(i)).setAttribute("name", nameValue);	
				
	}
	
	/**Permite setear al documento destino el nombre del paquete indicado en el primer parámetro. 
	 * @param packageValue
	 * 			el nombre del paquete que será seteado.
	 * @param dest
	 * 			documento que será modificado con el nombre del paquete que figura en el primer parámetro
	 * </BR>NOTA: el documento representa una clases java y su estructura debe corresponderse con la impuesta
	 *  por la biblioteca Java2XML.*/
	public void setPackage(String packageValue, Document dest){		
		
		Element packageElement;
		try {
			packageElement = (Element)xpath.evaluate("/"+CLASSFILENAME+"/"+PACKAGE,dest,XPathConstants.NODE);
				
			if (packageValue.compareTo("") != 0){
				if (packageElement == null){
					//chequear si funciona
					packageElement = (Element)xpath.evaluate("//[id=\"package\"]", preBuildStructures, XPathConstants.NODE);
					packageElement.setAttribute("name", packageValue);
					
					Node node = (Node)xpath.evaluate("//"+IMPORT+"[1]", dest, XPathConstants.NODE);
					if (node == null)
						node = (Node)xpath.evaluate("//"+CLASS, dest, XPathConstants.NODE);
					dest.insertBefore(packageElement, node);				
				}
				else
					packageElement.setAttribute("name", packageValue);
				
				System.out.print("package "+packageValue);
			}
			else			
				System.out.print("package default");
		} catch (XPathExpressionException e) {
			System.out.println("[ERR] Falló el seteo del paquete");
			e.printStackTrace();
		}		
	}
	
		
	/**Permite setear en el documento destino el nombre del paquete en el que está contenido el documento origen. 
	 * @param source
	 * 			documento del cual se extraerá el nombre del paquete al que pertenece la clase que representa.
	 * @param dest
	 * 			documento que será modificado con el nombre del paquete que figura en el documento source
	 * </BR>NOTA: ambos documentos representan clases java y sus estructuras responden a la impuesta por la
	 * biblioteca Java2XML.*/	
	public void setPackage(Document source, Document dest) throws XPathExpressionException{
					
		String packageValue = (String)xpath.evaluate("/"+CLASSFILENAME+"/"+PACKAGE+"/@name",source,XPathConstants.STRING);
		this.setPackage(packageValue, dest);		
						
	}
	
	
	
	/**Permite setear el atributo "name" de un elemento type. Dicho elemento es utilizado para representar el tipo
	 * de una variable, constante, parámetro o retorno de una función.
	 * Como consecuencia de la invocación al método se modifica el documento del segundo parámetro.
	 * @param typeValue
	 * 				valor que tomará el nombre de un elemento type
	 * @param dest
	 * 				documento donde se halla el elemento type que recibirá la modificación
	 * @param destLocation
	 * 				expresión XPath que indica el elemento type a modificar contenido dentro del documento dest*/
	public void setType(String typeValue, Document dest, String destLocation) throws XPathExpressionException{
		this.setType(typeValue, dest.getDocumentElement(), destLocation);
	}
	
	
	/**Permite setear el atributo "name" de un elemento type. Dicho elemento es utilizado para representar el tipo
	 * de una variable, constante, parámetro o retorno de una función.
	 * Como consecuencia de la invocación al método se modifica el elemento dest que corresponde al segundo parámetro.
	 * @param typeValue
	 * 				valor que tomará el nombre de un elemento type
	 * @param dest
	 * 				elemento que recibirá la modificación.
	 * @param destLocation
	 * 				expresión XPath que indica el elemento type a modificar contenido dentro del elemento dest*/
	public void setType(String typeValue, Element dest, String destLocation) throws XPathExpressionException{
				
		if (typeValue.compareTo("") != EQUAL){
			Element typeElement = (Element)xpath.evaluate(destLocation,dest,XPathConstants.NODE);
			if (typeElement != null){
				typeElement.setAttribute("name", typeValue);			
				if (primitivesTypes.contains(typeValue))
					typeElement.setAttribute("primitive", "true");
				System.out.print("type "+typeValue);
			}			
		}				
	}
	
	/**Copia todos los atributos del parámetro sourceElement en el parámetro destElement. Si un atributo se encuentra presente
	 * en ambos elementos, el valor en destElement tomará el correspondiente de sourceElement.  
	 * Como consecuencia de la invocación al método se modifica el parámetro destElement.
	 * @param sourceElement
	 * 				elemento del que se extraerán los atributos para ser copiados en el elemento destElement
	 * @param destElement
	 * 				elemento que recibirá los atributos y valores del sourceElement 
	 * @param clear
	 * 				si es true, los atributos contenidos en destElement que no se encuentran en sourceElement serán eliminados,
	 * 				por el contrario si esta en false los mismos se preservarán.  
	 */
	public void copyAttributes(Element sourceElement, Element destElement, boolean clear){			
			 
			if (clear){
				NamedNodeMap destAttributes = destElement.getAttributes();			
				for (int i = 0; i < destAttributes.getLength(); i++)
					destElement.removeAttributeNode((Attr)destAttributes.item(i));
			}
			//seteo cada atributo-valor de typeElement en el elemento type dest 
			NamedNodeMap attributes = sourceElement.getAttributes();
			for (int j = 0; j < attributes.getLength(); j++){
				Node nodeToAdd = destElement.getOwnerDocument().importNode(attributes.item(j), true);
				destElement.setAttributeNode((Attr)nodeToAdd);
			}		
	}
	
	/**
	 * Método encargado de crear un {@link Element} con el nombre {@link tagName} y setea el atributo
	 * name del mismo con el valor {@link name}. El nuevo Element es asociado a {@link doc}.
	 * 
	 * @param doc documento en el cual se creará el nuevo {@link Element}.
	 * @param tagName nombre del nuevo {@link Element}.
	 * @param name valor para el atributo name.
	 * @return El nuevo {@link Element} creado.
	 */
	public Element createNewTag(Document doc,String tagName ,String name) {
		Element retNode = doc.createElement(tagName);
		if (!name.equals("")||!name.equals(null))
			retNode.setAttribute("name", name);
		return retNode;
	}
	
	/**
	 * El método genera un Element que representa una asignación con el valor a izquiera {@link leftValue} que pertenece
	 * a una variable de instancia (accede mediante this) y a derecha {@link rightValue}, y la asocia {@link doc}.
	 * Ejemplo:
	 * 			this.leftValue = rightValue;
	 * 
	 * @param doc Document al que se asocia el nuevo Element que representa una asignación.
	 * @param leftValue Valor del lado izquierdo de la asignación.
	 * @param rightValue Valor del lado derecho de la asignación.
	 * @throws XPathExpressionException
	 */
	protected Element setAssingmentValues(Document doc,String leftValue, String rightValue) throws XPathExpressionException {
		Element assignment = (Element) xpath.evaluate("structures/structure[@id=\"constructorAssignment\"]/"+ASIGMENT, this.preBuildStructures,XPathConstants.NODE);
		Element lvalue = (Element)xpath.evaluate(ASSIGLEFTVALUE+"/"+FIELDACCESS, assignment, XPathConstants.NODE);
		Element rvalue = (Element)xpath.evaluate(VARREF, assignment, XPathConstants.NODE);
		lvalue.setAttribute("field", leftValue);
		rvalue.setAttribute("name", rightValue);
		return (Element)doc.importNode(assignment, true);
	}
	
	/**
	 * Método encargado de devolver el Element donde se encuentra la delcaración de
	 * la variable pasada como parámetro.
	 * @param var
	 * @return
	 */
	public Element getDeclaration(Element var){
		if((Element)var.getElementsByTagName(LOCALVARIABLE).item(FIRST)!=null)
			// si la delcaración se encuentra en la linea de var (o sea, si se declara un local-variable en la misma linea del SD)
			return var;
		else{
			Element father = (Element) var.getParentNode();
			return this.findDeclare((Element)father.getChildNodes().item(0), var, var);
		}
	}
	
	
	/**
	 * Método que busca la declaración de una variable local a un método de forma recursiva.
	 * @param brother
	 * 		  Nodo hermano de {@link actualLimit}
	 * @param actualLimit
	 * 		  Nodo hermano de {@link brother} que es el límite de consideración en la recursión.
	 * @param var
	 * 		  Variable de la que se desea encontrar la declaración.
	 * @return Element que representa la declaración de la variable <B>var</B>. Null si no se encontró
	 * 		   la declaración dentro del método donde se está buscando
	 */
	private Element findDeclare(Element brother,Element actualLimit,Element var) {
		if (brother.getTagName().equals(METHOD))//llegué a la declaración del método
			return null;
		if ( (brother !=null) && (this.isDeclaration(var,brother)) )
			return brother;
		else
			if(brother.compareDocumentPosition(var) == Element.DOCUMENT_POSITION_FOLLOWING)
				return this.findDeclare((Element) brother.getNextSibling(),actualLimit,var);
			else
				if (brother.compareDocumentPosition(actualLimit) == 0){
					Element father = (Element) brother.getParentNode();
					Element bigFather = (Element) father.getParentNode();
					return this.findDeclare((Element) bigFather.getChildNodes().item(FIRST),father,var);
				}									
		return null;
	}
	
	
	/**
	 * Método encargado de comprarar si el Element <B>item</B> es la declaración de la variable <B>var</B>
	 * @param var 
	 * 		  representa un nodo declaración, o bien, un nodo asignación del cual se extrae la variable
	 * 		  del lado izquierdo 		  
	 * @param item
	 * 		  Element del que se pretende saber si corresponde a la declaración del parámetro <B>var</B>.
	 * @return true si <B>item</B> es la declaración de <B>var</B>, false en caso contrario.
	 */
	private boolean isDeclaration(Element var, Element item) {
		String hasDeclaration = item.getTagName();
		if ( (hasDeclaration!=null) && (hasDeclaration.equals(LOCALVARIABLE)) )
			if (item.getAttribute("name").equals(this.getVarNameInAssignment(var)))
				return true;
		return false;
	}
	
	/**Sirve para extraer el nombre de la variable local a un método partiendo de su declaración o
	 * una sentencia de asignación.
	 * @param assignment
	 * 			elemento que representa una sentencia de declaración, una declaración con asignación
	 * 			incluida o simplemente una asignación.
	 * @return nombre de la variable declarada o asignanada*/	
	public String getVarNameInAssignment(Element assignment){
		String varName = assignment.getAttribute("name");		   
		//si assignment no tiene el nombre de la variable 
		//(xq resultó que se declaró más arriba de la línea donde se hace la asignación) 
		if (varName.compareTo("") == EQUAL){ 
			String varNameLocation = ASSIGLEFTVALUE+"/"+VARREF+"/@name";  
			try {
				varName = (String)xpath.evaluate(varNameLocation, assignment, XPathConstants.STRING);
			} catch (XPathExpressionException e) {
				System.out.println("Falló recuperación del nombre de la variable contenida en una asignación");
				e.printStackTrace();
			} 
		}
		return varName;		
	}
	
	
	/**Agrega una excepción a la lista de excepciones arrojadas por el método que se indican en su 
	 * declaración.
	 * @param method
	 * 			Element que representa el método al que se quiere anexar el lanzamiento de una excepción
	 * @param exception
	 * 			String que indica el nombre de la excepción lanzada que se anexará a la declaración del método
	 * */
	public void addExceptionThrown(Element method, String exception){
		try{
			if (!(Boolean)xpath.evaluate("self::"+THROWS+"[@exception='"+exception+"']", method, XPathConstants.BOOLEAN)){
				Element throwsSent = method.getOwnerDocument().createElement(THROWS);
				throwsSent.setAttribute("exception", exception);
				Element body = (Element)xpath.evaluate("self::"+BODYMETHOD, method, XPathConstants.NODE);
				method.insertBefore(throwsSent, body);
			}			
		}catch(XPathExpressionException e){
			e.printStackTrace();
		}
	}
	
	/**retorna el método al que pertenece una sentencia
	 * @param sentence
	 * 			sentencia de la cual se pretende conocer el método al que pertenece
	 * @return retorna el element del método al que pertenece la sentencia. Null si no pertenece a ningún método o si la sentencia misma es
	 * un elemento método.
	 **/
	public Element getOwnerMethod(Node sentence){
		try {
			return (Element)xpath.evaluate("ancestor::"+BODYMETHOD+"[1]", sentence, XPathConstants.NODE);
		} catch (XPathExpressionException e) {			
			e.printStackTrace();
			return null;
		}
	}
	
	
	/**Permite obtener la expresion xpath que identifica unívocamente a un método java dentro de una clase,
	 * partiendo de su signatura. 
	 * @param method
     *             Element que representa la signatura de un método java              
     * @return     String que representa la expresión XPath del método indicado en el primer parámetro</BR>
     *             La expresión resultante respetará información acerca de:
     *                    -nombre del método
     *                    -tipo devuelto
     *                    -tipo y posición de cada parámetro formal
     *                Esta expresión puede ser empleada en una consulta XPath para hallar por ejemplo el cuerpo de dicho
     *                método en un documento. Una aplicación puede verse cuando se pretende conocer la implementación
     *                de un método por parte de una clase que extiende una interface que declara la signatura del método
     *                en cuestión.</BR>
     *             Ejemplo:
     *                 se tiene la siguiente declaración de método: public long suma(int a, int b);
     *                 la expresion xpath resultante será</BR>
     *                //method[@name="suma"][type[@name="long"] and formal-arguments[formal-argument[type[@name="int"]] and formal-argument[type[@name="int"]]] and block]"</BR>
     *                A partir de dicha expresion puedo traer desde un documento el nodo que la cumpla y así obtener todos los demás datos del método como por ejemplo el cuerpo
     *                del mismo.                
     * @throws XPathExpressionException
     * </BR>NOTA: los throws de la signatura del método no son tenidos en cuenta para armar la expresión xpath*/
   
    public String getXpathMethodExpression(Element method) throws XPathExpressionException{
        String retorno = new String("//"+METHOD);
        retorno+= "[@name=\""+(String)xpath.evaluate("@name", method, XPathConstants.STRING)+"\"]";
        retorno+= "["+TYPE+"[@name=\""+(String)xpath.evaluate(TYPE+"/@name", method, XPathConstants.STRING)+"\"]";
        retorno+=" and "+ALLPARAMS;
        NodeList argumentsType = (NodeList)xpath.evaluate(ALLPARAMS+"/"+PARAM+"/"+TYPE+"/@name", method, XPathConstants.NODESET);
       
        if(argumentsType.getLength() > 0){
            retorno+="[";           
            for(int i = 0; i < argumentsType.getLength(); i++){
                String typeName = argumentsType.item(i).getNodeValue();
                retorno+=PARAM+"["+TYPE+"[@name=\""+typeName+"\"]]";
               
                //si no llegué al último argumento
                if (i < argumentsType.getLength()-1)
                    retorno+=" and ";       
            }
        }       
        retorno+="] and "+BODYMETHOD+"]";
        return retorno;
    }
    
    /**
     * Método encargado de evaluar si el String pasado como parametro representa un tipo primitivo de dato. De ser asi devuelve true,
     * en caso contrario devuelve false.
     * @param type	tipo de dato a evaluar.
     * @return
     */
    public boolean isPrimitive(String type){
    	if (this.primitivesTypes.contains(type))
    		return true;
    	return false;
    }
    
    
    /**Convierte una clase fuente de java en un documento DOM
	 * @param src
	 * 			es la ruta del archivo del que se desea obtener el documento que lo representa
	 * @return org.w3c.dom.Document que representa al archivo fuente de java indicado en el parámetro*/
	public static org.w3c.dom.Document classToDOM(String src) {
		IXMLElement element = null;
		File file = new File(src);        
        try{
        	FileReader reader = new FileReader(src);
        	element = Java2XML.convertToXML(reader, file.getName());
        }catch (FileNotFoundException e){        	
        	e.printStackTrace();
        }catch(JXMLException e){
        	e.printStackTrace();
        }
        if (element == null){
        	System.out.println("Ocurrio un error levantando la clase " + src);
        	return null;
        }
        Document doc = null;
        try {
			doc = Domifier.toDom(element);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		return doc;
	}
	


}
